package com.tuhao.www.filter;

import org.apache.log4j.Logger;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * @author tuhao on 2017/3/30.
 */
public class SqlInjectFilter implements Filter {

    private static String ERROR_CONTROLLER = "/error/404.jsp";

    private static final Logger log = Logger.getLogger(SqlInjectFilter.class);

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        String error = arg0.getInitParameter("error");
        if (error != null) {
            ERROR_CONTROLLER = error;
        }
    }

    @Override
    public void doFilter(ServletRequest args0, ServletResponse args1, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) args0;
        HttpServletResponse response = (HttpServletResponse) args1;

        // 获得所有请求参数名
        Enumeration<String> params = req.getParameterNames();
        //获取请求地址开始：不能再请求地址做防注入，原因是开发工作者经常使用比如select,save,delete做请求地址
        /*String url = req.getServletPath();
        if (sqlValidate(url)) {
            log.error("有sql注入风险，请求参数为url：" + url);
            req.getRequestDispatcher(ERROR_CONTROLLER).forward(req, response);
        }*/
        //请求地址防注入结束
        String sql = "";
        while (params.hasMoreElements()) {

            // 得到参数名
            String name = params.nextElement().toString();

            // 得到参数对应值
            String[] value = req.getParameterValues(name);
            for (int i = 0; i < value.length; i++) {
                sql = sql + value[i];
            }
        }

        // 有sql关键字，跳转到error.html
        if (sqlValidate(sql)) {
            log.error("有sql注入风险，请求参数为：" + sql);
            req.getRequestDispatcher(ERROR_CONTROLLER).forward(req, response);
        } else {
            chain.doFilter(args0, args1);
        }
    }

    // 效验请求参数是否含有查询语句的重点单词
    protected static boolean sqlValidate(String str) {
        str = str.toLowerCase().trim();// 统一转为小写
        //过滤的关键字
        String badStr = "'| ' | db | save | find | and | exec | execute | insert | select | delete | update | count | drop | * | % | chr | mid | master | truncate | "
                + "char | declare | sitename | net user | xp_cmdshell  | or | - | +  | like | and | exec | execute | insert | create | drop | " + "table | from | grant | use | group_concat | column_name | "
                + "information_schema.columns | table_schema | union | where | select | delete | update | order | by | count | * | " + "chr | mid | master | truncate | char | declare | or | - | -- | +  | like | // | / | % | #";
        //前台一款插件使用时候会有问题，所以暂时给注释了，
        badStr = "";
        String[] badStrs = badStr.split("\\|");
        /*for (int i = 0; i < badStrs.length; i++) {
            String bad = badStrs[i].trim();
            if (str.indexOf(bad) >= 0) {
                return true;
            }
        }*/
        return false;
    }

    public static void main(String args[]) {
        String sql = "[{\"\":\"\",\"\":},{\"\":\"\",\"\":},{\"\":\"\",\"\":\",,\"},{\"\":\"\",\"\":0},{\"\":\"\",\"\":},{\"\":\"\",\"\":\"id\"},{\"\":\"\",\"\":\"\"},{\"\":\"\",\"\":\"\"},{\"\":\"\"}]";

        System.err.println(sqlValidate(sql));
    }
}
